package com.inspur.edp.bef.bizentity.util;


import com.inspur.edp.bef.bizentity.GspBizEntityElement;
import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspDeleteRuleType;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.GspProject;
import com.inspur.edp.lcm.metadata.api.entity.MetadataProject;
import com.inspur.edp.lcm.metadata.api.service.MetadataProjectService;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.lcm.metadata.api.service.RefCommonService;
import com.inspur.edp.svc.reference.check.api.IReferenceCfgManager;
import com.inspur.edp.svc.reference.check.api.ReferenceConfigInfo;
import com.inspur.edp.svc.reference.check.api.ReferenceType;
import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.dbInfo.ColumnMapType;
import com.inspur.edp.udt.designtime.api.entity.element.UdtElement;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import lombok.var;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

public class ReferenceService {

	private IReferenceCfgManager manager = SpringBeanUtils.getBean(IReferenceCfgManager.class);
	private static final String identifier = "/";
	private static final String SERVICEID=  "Inspur.Gsp.Cef.Core.BEDeleteService.CheckReference";
	private java.util.ArrayList<String> ids = new java.util.ArrayList<String>();

	public String getServiceUnitCode() {
		return serviceUnitCode;
	}

	public void setServiceUnitCode(String serviceUnitCode) {
		this.serviceUnitCode = serviceUnitCode;
	}
	private String serviceUnitCode;

	public RefCommonService getRefCommonService() {
		return refCommonService;
	}

	public void setRefCommonService(RefCommonService refCommonService) {
		this.refCommonService = refCommonService;
	}

	private  RefCommonService refCommonService;
	public ReferenceService()
	{

	}
	public static  ReferenceService getInstance(){
		return new ReferenceService();
	}
	//注册引用
	public final void registerReference(GspMetadata metadata)
	{
		parseMetadata(metadata);
	}



	//解析be元数据
	private void parseMetadata(GspMetadata md)
	{
		GspBusinessEntity be = (GspBusinessEntity)((md.getContent() instanceof GspBusinessEntity) ? md.getContent() : null);
		String su = getSU(md); //引用关联BE所属的SU
		String referre = be.getDotnetGeneratedConfigID(); //引用关联BE的BefConfig
		if (be == null)
			return;
		java.util.ArrayList<ReferenceConfigInfo> list = new java.util.ArrayList<ReferenceConfigInfo>();
		//遍历be各个节点
		for (var item : be.getAllObjectList())
		{
			var obj = (GspBizEntityObject)item;
			var elements = obj.getAllElementList(true);
			//遍历节点的所有属性，并找出设置关联的属性字段
			for (var element : elements)
			{
				var field = (GspBizEntityElement)element;
				//TODO: 此方法暂时用不到, 多值udt上的关联将来考虑支持
				//DealUdt(field,su,referre,be.MainObject.getCode(),obj.getCode(),list);
				if (field.getObjectType() == GspElementObjectType.Association)
				{
					var associations = field.getChildAssociations();
					for (var assocaition : associations)
					{
						if (assocaition.getAssoModelInfo() == null || StringUtil.checkNull(assocaition.getAssoModelInfo().getModelConfigId()) || assocaition.getDeleteRuleType()!= GspDeleteRuleType.Refuse)
						{
							continue;
						}

						String befConfig = assocaition.getAssoModelInfo().getModelConfigId(); //关联的BE的BefConfig
						String mainCode = assocaition.getAssoModelInfo().getMainObjCode(); //关联的BE的主节点编号
						String nodeCode = assocaition.getRefObjectCode(); //关联的BE节点编号
						if (mainCode.equals(nodeCode))
						{
							nodeCode = "RootNode";
						}
						String source = befConfig + identifier + nodeCode;
						// string su = getSU(md);//引用关联BE所属的SU
						ReferenceType referType = ReferenceType.BE;
						String refPropName = be.getDotnetGeneratedConfigID() +
								identifier + be.getMainObject().getCode() +
								identifier + obj.getCode() + identifier +
								field.getLabelID();
						//引用关联BE的字段
						ReferenceConfigInfo info = new ReferenceConfigInfo();
						info.setId(UUID.randomUUID().toString());
						info.setSource(source);
						info.setReferenceType(referType);
						info.setSu(su);
						info.setReferrer(referre);
						info.setRefPropName(refPropName);
						info.setServiceId(SERVICEID);
						info.setWarningMessage(String.format("要删除的数据已经被【%1$s】上的【%2$s】使用，无法删除！",item.getName(),field.getName()));
						//
						info.setCreator(CAFContext.current.getCurrentSession().getUserName());
						info.setCreatedTime(CAFContext.current.getCurrentDateTime());
						info.setLastModifiedTime(CAFContext.current.getCurrentDateTime());
						info.setLastModifier(CAFContext.current.getCurrentSession().getUserName());
						list.add(info);
					}

				}
			}
			java.util.HashMap<String, ReferenceConfigInfo> result = getDBRecord(su, referre);
			java.util.ArrayList<ReferenceConfigInfo> dbInfo = new java.util.ArrayList<ReferenceConfigInfo>();

			for (var value : result.values())
			{
				dbInfo.add(value);
			}
			registerRefer(list, dbInfo);
		}
	}

	private String getSU(GspMetadata metadata) {
		if(serviceUnitCode==null){
			MetadataProjectService service = SpringBeanUtils.getBean(MetadataProjectService.class);
			MetadataService metadataService=SpringBeanUtils.getBean(MetadataService.class);
			MetadataProject metadataInfo = service.getMetadataProjInfo(metadata.getRelativePath());
			GspProject projInfo = metadataService.getGspProjectInfo(metadataInfo.getProjectPath());
			serviceUnitCode= projInfo.getServiceUnitCode();
		}
		return serviceUnitCode;
	}


	//更新或注册元数据关联记录信息
	private void registerRefer(java.util.ArrayList<ReferenceConfigInfo> newInfo, java.util.ArrayList<ReferenceConfigInfo> dbInfo)
	{
		java.util.ArrayList<ReferenceConfigInfo> delete = new java.util.ArrayList<ReferenceConfigInfo>();
		java.util.ArrayList<ReferenceConfigInfo> update = new java.util.ArrayList<ReferenceConfigInfo>();
		java.util.ArrayList<ReferenceConfigInfo> insert = new java.util.ArrayList<ReferenceConfigInfo>();

		for (var item : dbInfo)
		{
			int flag = 0;

			for (var childItem : newInfo)
			{
				if (childItem.getRefPropName().equals(item.getRefPropName()))
				{
					if (!childItem.getSource().equals(item.getSource()) || !childItem.getWarningMessage().equals(item.getWarningMessage()))
					{
						item.setSource(childItem.getSource());
						item.setWarningMessage(childItem.getWarningMessage());
						update.add(item);
					}
					break;
				}
				flag++;
			}
			if (flag == newInfo.size())
			{
				delete.add(item);
			}

		}

		for (var item : newInfo)
		{
			int flag = 0;

			for (var childItem : dbInfo)
			{
				if (childItem.getRefPropName().equals(item.getRefPropName()))
				{
					break;
				}
				flag++;
			}
			if (flag == dbInfo.size())
			{
				insert.add(item);
			}
		}

		for (var item : delete)
		{
			manager.delete(item.getId());
		}

		for (var item : insert)
		{
			manager.register(item);
		}

		for (var item : update)
		{
			manager.update(item);
		}
	}

	//获取元数据的历史关联记录
	private java.util.HashMap<String, ReferenceConfigInfo> getDBRecord(String su, String referre)
	{
		java.util.HashMap<String, ReferenceConfigInfo> result = new java.util.HashMap<String, ReferenceConfigInfo>();
      //获取数据库be上已有关联记录
        List<ReferenceConfigInfo> dbRecord=manager.query(item ->item.getReferenceType()==ReferenceType.BE && item.getSu().equals(su) && item.getReferrer().equals(referre));
		if(dbRecord==null)
             return result;
		for (var record : dbRecord)
		{
			result.put(record.getId(), record);
		}
		return result;
	}


	//Udt的关联解析
	private void dealUdt(IGspCommonField element, String su, String referer, String main, String node, ArrayList<ReferenceConfigInfo> list)
	{
		if (element.getIsUdt())
		{
			String udtId = element.getUdtID();
			GspMetadata md = getMetadata(udtId);
			UnifiedDataTypeDef udt = (UnifiedDataTypeDef)((md.getContent() instanceof UnifiedDataTypeDef) ? md.getContent() : null);
			if (udt == null)
			{
				return;
			}
			if ((SimpleDataTypeDef)udt== null)
			{
				ComplexDataTypeDef cudt = (ComplexDataTypeDef)udt;
				if (cudt.getDbInfo().getMappingType() == ColumnMapType.MultiColumns)
				{

					var elements = cudt.getElements();

					for (var item : elements)
					{
						UdtElement udtElement = (UdtElement)item;
						dealUdt(item, su, referer, main, node, list);
						if (udtElement.getObjectType() == GspElementObjectType.Association)
						{

							var associations = udtElement.getChildAssociations();

							for (var assocaition : associations)
							{
								GspMetadata refMd = getMetadata(assocaition.getRefModelID());

								var beEntity = (GspBusinessEntity)((refMd.getContent() instanceof GspBusinessEntity) ? refMd.getContent() : null);
								String befConfig = beEntity.getDotnetGeneratedConfigID();
								String mainCode = beEntity.getMainObject().getCode();
								String nodeCode = assocaition.getRefObjectCode();
								if (mainCode.equals(nodeCode))
								{
									nodeCode = "RootNode";
								}
								String source = befConfig + identifier + nodeCode;
								ReferenceType referType = ReferenceType.BE;
								String refPropName = referer + identifier + main + identifier + node + identifier + GetUdtPersistColuName(element, udtElement.getLabelID());
								ReferenceConfigInfo info = new ReferenceConfigInfo();
								info.setId(UUID.randomUUID().toString());
								info.setSource(source);
								info.setReferenceType(referType);
								info.setSu(su);
								info.setReferrer(referer);
								info.setRefPropName(refPropName);
								info.setServiceId(SERVICEID);
								//
								info.setCreator(CAFContext.current.getCurrentSession().getUserName());
								info.setCreatedTime(CAFContext.current.getCurrentDateTime());
								info.setLastModifiedTime(CAFContext.current.getCurrentDateTime());
								info.setLastModifier(CAFContext.current.getCurrentSession().getUserName());
								list.add(info);
							}
						}
					}
				}
			}
			else
			{
				SimpleDataTypeDef sudt = (SimpleDataTypeDef)udt;
				if (sudt.getObjectType() == GspElementObjectType.Association)
				{

					var associations = sudt.getChildAssociations();

					for (var assocaition : associations)
					{
						GspMetadata refMd =getMetadata(assocaition.getRefModelID());

						var beEntity = (GspBusinessEntity)((refMd.getContent() instanceof GspBusinessEntity) ? refMd.getContent() : null);
						String befConfig = beEntity.getDotnetGeneratedConfigID();
						String mainCode = beEntity.getMainObject().getCode();
						String nodeCode = assocaition.getRefObjectCode();
						if (mainCode.equals(nodeCode))
						{
							nodeCode = "RootNode";
						}
						String source = befConfig + identifier + nodeCode;
						ReferenceType referType = ReferenceType.BE;
						String refPropName = referer + identifier + main + identifier + node + identifier + element.getCode();
						ReferenceConfigInfo tempVar2 = new ReferenceConfigInfo();
						tempVar2.setId(UUID.randomUUID().toString()); 
						tempVar2.setSource(source); 
						tempVar2.setReferenceType(referType); 
						tempVar2.setSu(su);
						tempVar2.setReferrer(referer);
						tempVar2.setRefPropName(refPropName); 
						tempVar2.setServiceId(SERVICEID); 
						ReferenceConfigInfo info = tempVar2;
						list.add(info);
					}
				}
			}

		}
	}

	private GspMetadata getMetadata(String metadataId) {
		if(refCommonService==null){
			return SpringBeanUtils.getBean(RefCommonService.class).getRefMetadata(metadataId);
		}
		return refCommonService.getRefMetadata(metadataId);
	}
	

	private String GetUdtPersistColuName(IGspCommonField field, String code)
	{
		return field.getLabelID() + "_" + code;
	}
	
	
}

